package net.orange.framework.model;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.Set;

import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.ManyToMany;
import javax.persistence.ManyToOne;
import javax.persistence.Table;

import net.orange.architecture.model.BaseValueObject;
import net.orange.architecture.validator.NotDulicateValidator;
import net.orange.architecture.validator.StringNotNullValidator;
import net.orange.architecture.validator.Validator;
import net.orange.architecture.web.LocalizationMessage;
import net.orange.framework.validator.MenuCodeValidator;
import net.orange.framework.validator.MenuParentValidator;

/**
 * The system menu for the users.The menu is assign to the special groups.
 * System will assign the menus when the user login on the system according
 * their groups.
 */
@Entity
@Table(name = "t_menu")
public class Menu extends BaseValueObject {

	private static final long serialVersionUID = -6342277129742423385L;

	private static String MESSAGE_RESOURCE = "net/orange/conf/lang/fw";
	/**
	 * The menu code
	 */
	@Column(name = "menu_code")
	private String menu_code;

	/**
	 * The menu name
	 */
	@Column(name = "menu_name")
	private String menu_name;

	/**
	 * The menu label
	 */
	@Column(name = "label")
	private String label;

	/**
	 * The label index for the localization.
	 */
	@Column(name = "labelIndex")
	private String labelIndex;

	/**
	 * The menu url
	 */
	@Column(name = "url")
	private String url;

	/**
	 * The menu level
	 */
	@Column(name = "menulevel")
	private int level;

	/**
	 * The parent menu
	 */
	@ManyToOne(cascade = CascadeType.REFRESH, fetch = FetchType.EAGER)
	@JoinColumn(name = "parent", insertable = true, updatable = true)
	private Menu parent;

	/**
	 * The menu sequence in web page.
	 */
	@Column(name = "seq")
	private int seq;

	/**
	 * The assigned groups
	 */
	@ManyToMany(targetEntity = net.orange.framework.model.Group.class, cascade = { CascadeType.ALL }, fetch = FetchType.EAGER)
	@JoinTable(name = "t_menu_group", joinColumns = { @JoinColumn(name = "menu_pk") }, inverseJoinColumns = { @JoinColumn(name = "group_pk") })
	private Set<Group> groups = new HashSet<Group>();

	/**
	 * The description
	 */
	@Column(name = "description")
	private String description;

	/**
	 * @return Returns the description.
	 */
	public String getDescription() {
		return description;
	}

	/**
	 * @return Returns the label.
	 */
	public String getLabel() {
		return label;
	}

	/**
	 * @return Returns the level.
	 */
	public int getLevel() {
		return level;
	}

	/**
	 * @return Returns the menu_code.
	 */
	public String getMenu_code() {
		return menu_code;
	}

	/**
	 * @return Returns the menu_name.
	 */
	public String getMenu_name() {
		return menu_name;
	}

	/**
	 * @return Returns the seq.
	 */
	public int getSeq() {
		return seq;
	}

	/**
	 * @return Returns the url.
	 */
	public String getUrl() {
		return url;
	}

	/**
	 * @param description
	 *            The description to set.
	 */
	public void setDescription(String description) {
		this.description = description;
	}

	/**
	 * @param label
	 *            The label to set.
	 */
	public void setLabel(String label) {
		this.label = label;
	}

	/**
	 * @param level
	 *            The level to set.
	 */
	public void setLevel(int level) {
		this.level = level;
	}

	/**
	 * @param menu_code
	 *            The menu_code to set.
	 */
	public void setMenu_code(String menu_code) {
		this.menu_code = menu_code;
	}

	/**
	 * @param menu_name
	 *            The menu_name to set.
	 */
	public void setMenu_name(String menu_name) {
		this.menu_name = menu_name;
	}

	/**
	 * @param seq
	 *            The seq to set.
	 */
	public void setSeq(int seq) {
		this.seq = seq;
	}

	/**
	 * @param url
	 *            The url to set.
	 */
	public void setUrl(String url) {
		this.url = url;
	}

	/**
	 * @return Returns the encodeURL.
	 */
	public String getEncodeURL() {
		return url;
	}

	/**
	 * @return Returns the parent.
	 */
	public Menu getParent() {
		return parent;
	}

	/**
	 * @param parent
	 *            The parent to set.
	 */
	public void setParent(Menu parent) {
		this.parent = parent;
	}

	/**
	 * @return the labelIndex
	 */
	public String getLabelIndex() {
		return labelIndex;
	}

	/**
	 * @param labelIndex
	 *            the labelIndex to set
	 */
	public void setLabelIndex(String labelIndex) {
		this.labelIndex = labelIndex;
	}

	/**
	 * @return The label text after localization
	 * @throws Exception
	 */
	public String getLabelText() throws Exception {
		if (labelIndex == null || labelIndex.length() <= 0)
			return label;

		LocalizationMessage message = LocalizationMessage
				.getInstance(MESSAGE_RESOURCE);

		return message.get(labelIndex);
	}

	/**
	 * @return Returns the groups.
	 */
	public Set<Group> getGroups() {
		return groups;
	}

	/**
	 * @param groups
	 *            The groups to set.
	 */
	public void setGroups(Set<Group> groups) {
		this.groups = groups;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * net.orange.architecture.model.BaseValueObject#satisfy(java.util.Collection
	 * )
	 */
	public boolean satisfy(Collection<String> msg) throws Exception {
		if (msg == null)
			msg = new ArrayList<String>();

		Validator validator = new Validator(msg);

		validator.add(new StringNotNullValidator(getMenu_code(), "code"));
		validator.add(new StringNotNullValidator(getMenu_name(), "name"));
		validator.add(new StringNotNullValidator(getLabel(), "label"));
		// validator.add(new NumberNotNullValidator(getLevel(), "level"));
		validator.add(new NotDulicateValidator(this, "menu_code", "menu"));
		validator.add(new MenuParentValidator(this));
		validator.add(new MenuCodeValidator(this));

		validator.validate();

		return (msg == null || msg.size() <= 0);
	}

}
